/***************************************************************************
 * File name: q4.c
 *
 * Authors:  Tomer Filiba		Reuven Horon
 *           037013075			066729740
 *           sebulba@t2			sreuvenh@t2
 *
 * Exercise #: 5
 * Question #: 3 AND 4 (the two questions solved in one file)
 * Submission Date: 2/8/07
 **************************************************************************/

/*-------------------------------------------------------------------------
 * Include files:
 *------------------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>


/*=========================================================================
  Constants and definitions:
==========================================================================*/
#define SUCCESS				(0)
#define FAILURE				(1)
#define MIN_PHONE_NUMBER	(0)
#define MAX_PHONE_NUMBER	(9999)
#define MAX_ENTRIES			(MAX_PHONE_NUMBER - MIN_PHONE_NUMBER + 1)
#define MAX_NAME_SIZE		(32+32)
#define MAX_NAME_BUFSIZE	(MAX_NAME_SIZE + 1)

typedef enum {
	FALSE = (0 == 1),
	TRUE = (0 == 0),
} bool_t;


/*=========================================================================
  Global variables:
==========================================================================*/
char *tb_names[] = {"Eli Ben-Sasson", "Saher Esmeir", "Itai Sharon", "Andrey Klinger",
                    "Elad Haramaty", "Iddo Hanniel", "Miri Ben-Chen", "Osnat Tal",
                    "Sasha Skolozub", "Eli Biham", "Michael Elad", "Itai Dabran",
                    "Iddo Bentov", "Michael Heymann", "Michael Kaminski",
                    "Michael Lindenbaum", "Michael Shmoish"};
int tb_numbers[] = {4892, 4951, 4946, 3383, 5652, 3896, 4347, 4897, 4960, 4308, 4169, 
                    2908, 3372, 4163, 4360, 4331, 4302};
char sorted_numbers[MAX_ENTRIES][MAX_NAME_BUFSIZE] = {0};


/*=========================================================================
  Forward declarations:
==========================================================================*/
bool_t add_tb_entry(char sorted_numbers[][MAX_NAME_BUFSIZE],
					const char * firstname, const char * lastname, 
					int number);
bool_t remove_tb_entry(char sorted_numbers[][MAX_NAME_BUFSIZE], int number);
void sort_tb_by_number(char sorted_numbers[][MAX_NAME_BUFSIZE],
					   const char ** tb_names, const int * tb_numbers, 
					   int tb_size);
const char * search_tb(char sorted_numbers[][MAX_NAME_BUFSIZE], int number);
void print_tb(char sorted_numbers[][MAX_NAME_BUFSIZE]);
bool_t interactive_search(char sorted_numbers[][MAX_NAME_BUFSIZE]);


/*=========================================================================
  Function implementation:
==========================================================================*/

/*-------------------------------------------------------------------------
 * adds an entry to the telephone book
 *
 * parameters:
 * - sorted_numbers - the array of phonebook entries sorted by number
 * - firstname - the first name
 * - firstname - the last name
 * - number - the phone number
 *
 * return value: TRUE if the number was successfully added, or FALSE if
 * an error occured (number already exists, etc.)
 *
 * notes: the functions inserts a space between the first and last names
 *------------------------------------------------------------------------*/
bool_t add_tb_entry(char sorted_numbers[][MAX_NAME_BUFSIZE],
					const char * firstname, const char * lastname, 
					int number) 
{
	int len1 = strlen(firstname), len2 = strlen(lastname);
	
	if (number < MIN_PHONE_NUMBER || number > MAX_PHONE_NUMBER) {
		printf("Number out of range\n");
		return FALSE;
	}
	if (len1 + len2 > MAX_NAME_SIZE) {
		printf("Name too long\n");
		return FALSE;
	}
	number -= MIN_PHONE_NUMBER;
	if (sorted_numbers[number][0] != '\0') {
		printf("Number already exists\n");
		return FALSE;
	}
	strcpy(&sorted_numbers[number][0], firstname);
	sorted_numbers[number][len1] = ' ';
	strcpy(&sorted_numbers[number][len1+1], lastname);
	return TRUE;
}

/*-------------------------------------------------------------------------
 * removes an entry from the telephone book
 *
 * parameters:
 * - sorted_numbers - the array of phonebook entries sorted by number
 * - number - the phone number to remove
 *
 * return value: TRUE if the number was successfully removed, or FALSE if
 * an error occured (number does not exist, etc.)
 *------------------------------------------------------------------------*/
bool_t remove_tb_entry(char sorted_numbers[][MAX_NAME_BUFSIZE], int number) 
{
	if (number < MIN_PHONE_NUMBER || number > MAX_PHONE_NUMBER) {
		printf("Number out of range\n");
		return FALSE;
	}
	number -= MIN_PHONE_NUMBER;
	if (sorted_numbers[number][0] == '\0') {
		printf("Number does not exist in phonebook\n");
		return FALSE;
	}
	sorted_numbers[number][0] = '\0';
	return TRUE;
}

/*-------------------------------------------------------------------------
 * sorts the phone book by number
 * notes: this is an O(N) sort
 *
 * parameters:
 * - sorted_numbers - the array of phonebook entries sorted by number
 * - tb_names - the phonebook entry names
 * - tb_numbers - the phonebook entry numbers
 * - tb_size - the number of entries phonebook entry names
 *
 * return value: none
 *------------------------------------------------------------------------*/
void sort_tb_by_number(char sorted_numbers[][MAX_NAME_BUFSIZE],
					   const char ** tb_names, const int * tb_numbers, 
					   int tb_size)
{
	int i, j;
	
	for (i = 0; i < tb_size; i++) {
		j = tb_numbers[i] - MIN_PHONE_NUMBER;
		strcpy(sorted_numbers[j], tb_names[i]);
	}
}

/*-------------------------------------------------------------------------
 * searches the phonebook by number
 * notes: this is an O(1) search
 *
 * parameters:
 * - sorted_numbers - the array of phonebook entries sorted by number
 * - number - the number to search for
 *
 * return value: NULL if the entry does not exist, or a pointer to the
 * entry's name (string)
 *------------------------------------------------------------------------*/
const char * search_tb(char sorted_numbers[][MAX_NAME_BUFSIZE], int number)
{
	if (number < MIN_PHONE_NUMBER || number > MAX_PHONE_NUMBER) {
		return NULL;
	}
	number -= MIN_PHONE_NUMBER;
	if (sorted_numbers[number][0] == '\0') {
		return NULL;
	}
	else {
		return sorted_numbers[number];
	}
}

/*-------------------------------------------------------------------------
 * prints the telephone book's entries, sorted by number 
 *
 * parameters: 
 * - sorted_numbers - the array of phonebook entries sorted by number
 *
 * return value: none
 *------------------------------------------------------------------------*/
void print_tb(char sorted_numbers[][MAX_NAME_BUFSIZE])
{
	int i;
	
	/* iterate over the phone book and print all non-empty entries */
	for (i = 0; i < MAX_ENTRIES; i++) {
		if (sorted_numbers[i][0] != '\0') {
			printf("%-30s %d\n", sorted_numbers[i], i);
		}
	}
}

/*-------------------------------------------------------------------------
 * an interactive prompt for the user to enter commands (search, add, 
 * remove, print and quit)
 *
 * parameters: 
 * - sorted_numbers - the array of phonebook entries sorted by number
 *
 * return value: TRUE if the function terminates properly, FALSE otherwise
 * (e.g., EOF)
 *------------------------------------------------------------------------*/
bool_t interactive_search(char sorted_numbers[][MAX_NAME_BUFSIZE])
{
	bool_t show;
	int number;
	char * name = NULL;
	char buf[80], command[33], firstname[33], lastname[33];
	
	printf("This is Glorious Nation of Kazakhstan System of a Phonebook\n");
	printf("Carefull not break, you will be execute!!\n\n");
	printf("Type 'add <number> <firstname> <lastname>' to add an entry\n");
	printf("Type 'del <number>' to remove an entry\n");
	printf("Type 'print' to print the entire phonebook\n");
	printf("Type 'find <number>' to search for the given number\n");
	printf("Type 'Log off' to quit\n\n");
	
	while (TRUE) {
		printf("Command: ");
		
		/* read line and process it */
		if (fgets(buf, sizeof(buf), stdin) == NULL) {
			return FALSE;
		}
		if (buf[0] == '\n')
			continue;
		buf[strlen(buf)-1] = '\0';
		if (strcmp(buf, "Log off") == 0)
			return TRUE;
		
		/* dispatch relevant command (parsing with sscanf) */
		if (sscanf(buf, "%32s %d %32s %32s", command, &number, firstname, 
			lastname) == 4 && strcmp(command, "add") == 0) 
		{
			show = add_tb_entry(sorted_numbers, firstname, lastname, number);
		}
		else if (sscanf(buf, "%32s %d", command, &number) == 2 && 
			strcmp(command, "del") == 0) 
		{
			show = remove_tb_entry(sorted_numbers, number);
		}
		else if (sscanf(buf, "%32s %d", command, &number) == 2 && 
			strcmp(command, "find") == 0) 
		{
			name = search_tb(sorted_numbers, number);
			if (name != NULL) {
				printf("%-30s %d\n", name, number);
			}
			else {
				printf("Number not found\n");
			}
			show = FALSE;
		}
		else if (sscanf(buf, "%32s", command) == 1 && 
			strcmp(command, "print") == 0) 
		{
			show = TRUE;
		}
		else {
			printf("Invalid command\n");
			show = FALSE;
		}
		
		if (show)
			print_tb(sorted_numbers);
		printf("\n");
	}
}

/*-------------------------------------------------------------------------
 * The main program: sort phonebook by numbers and allow an interactive
 * prompt for adding, removing, printing and searching by number of
 * entries in the phonebook
 *-----------------------------------------------------------------------*/
int main(int argc, const char ** argv)
{
	const int tb_size = sizeof(tb_numbers) / sizeof(tb_numbers[0]);
	
	sort_tb_by_number(sorted_numbers, tb_names, tb_numbers, tb_size);
	if (!interactive_search(sorted_numbers)) {
		printf("Error reading stdin\n");
		return FAILURE;
	}
	
	return SUCCESS;
}

/**************************************************************************
			                          End of file
***************************************************************************/
